package com.mall.order.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import com.mall.common.exception.ServiceException;
import com.mall.course.course.domain.dto.CourseDto;
import com.mall.course.course.domain.vo.CourseVo;
import com.mall.course.course.mapper.CourseMapper;
import com.mall.goods.mapper.GoodsMapper;
import com.mall.goods.model.vo.GoodsSpecsVo;
import com.mall.goods.service.IGoodsSpecsService;
import com.mall.order.enums.*;
import com.mall.order.mapper.OrderTransMapper;
import com.mall.order.model.dto.*;
import com.mall.order.model.entity.OrderTransEntity;
import com.mall.order.model.vo.OrderItemVo;
import com.mall.thirdparth.pay.model.dto.OrderPayReqDto;
import org.joda.time.DateTime;
import com.mall.common.group.ValidGroup;
import com.mall.common.utils.DateUtils;
import com.mall.common.utils.SecurityUtils;
import com.mall.common.utils.bean.BeanValidators;
import com.mall.common.utils.uuid.IdUtils;
import com.mall.goods.model.vo.GoodsVo;
import com.mall.goods.service.IGoodsService;
import com.mall.order.mapper.OrderItemMapper;
import com.mall.order.mapper.OrderMapper;
import com.mall.order.model.entity.OrderEntity;
import com.mall.order.model.entity.OrderItemEntity;
import com.mall.order.model.vo.OrderVo;
import com.mall.order.service.IAppOrderService;
import com.mall.order.utils.OrderUtils;
import com.mall.thirdparth.pay.model.dto.OrderQueryReqDto;
import com.mall.thirdparth.pay.model.vo.OrderPayRespVo;
import com.mall.thirdparth.pay.model.vo.OrderQueryRespVo;
import com.mall.thirdparth.pay.service.OrderPayService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
public class AppOrderServiceImpl implements IAppOrderService {

    @Resource
    private IGoodsService goodsService;

    @Resource
    private OrderPayService orderPayService;

    @Resource
    private OrderMapper orderMapper;

    @Resource
    private OrderItemMapper orderItemMapper;

    @Resource
    private OrderTransMapper orderTransMapper;

    @Resource
    private CourseMapper courseMapper;

    @Resource
    private IGoodsSpecsService goodsSpecsService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public OrderDto create(AppCreateOrderDto dto) {

        AppOrderItemDto appOrderItemDto = dto.getItem();
        if (null == appOrderItemDto) {
            throw new ServiceException("商品不存在");
        }
        GoodsVo goodsVo = goodsService.selectGoodsById(appOrderItemDto.getGoodsId());
        if (null == goodsVo) {
            throw new ServiceException("商品不存在");
        }

        if ("1".equals(goodsVo.getNeedCourseFlag())) {
            if (null == dto.getSwimPlaceId()) {
                throw new ServiceException("游泳馆不能为空");
            }
            if (null == dto.getCourseId()) {
                throw new ServiceException("课程不能为空");
            }
            verifySignupNum(dto.getCourseId());
        }

        // 获取订单实体对象
        OrderDto order = getOrderByDto(dto);
        OrderItemDto orderItem = getOrderItemByDto(order, dto);

        orderMapper.insertOrder(order);
        orderItemMapper.insertOrderItem(orderItem);
        return order;
    }

    private OrderDto getOrderByDto(AppCreateOrderDto dto) {
        OrderDto order = new OrderDto();
        order.setSwimPlaceId(dto.getSwimPlaceId());
        order.setCourseId(dto.getCourseId());
        order.setUserId(dto.getUserId());
        order.setRemark(dto.getRemark());
        order.setSchoolId(dto.getSchoolId());
        order.setSchoolName(dto.getSchoolName());
        order.setGradeId(dto.getGradeId());
        order.setGradeName(dto.getGradeName());
        order.setClassId(dto.getClassId());
        order.setClassName(dto.getClassName());
        order.setParentName(dto.getParentName());
        order.setParentPhone(dto.getParentPhone());
        order.setStudentId(dto.getStudentId());
        order.setStudentName(dto.getStudentName());
        order.setPayType(dto.getPayType());
        // ID
        order.setId(Long.valueOf(IdUtils.getUniqueID()));
        // 订单号
        order.setOrderNo(OrderUtils.generateOrderSn());
        // 订单状态：待付款
        order.setOrderStatus(OrderStatusEnum.PENDING_PAY.value());
        // 创建时间
        order.setCreateTime(DateUtils.getNowDate());
        // 创建人
        order.setCreateBy(SecurityUtils.getNickName());
        // 创建人ID
        order.setCreateId(SecurityUtils.getUserId());
        return order;
    }

    private OrderItemDto getOrderItemByDto(OrderEntity order, AppCreateOrderDto dto) {
        AppOrderItemDto itemDto = dto.getItem();

        OrderItemDto item = new OrderItemDto();
        item.setId(Long.valueOf(IdUtils.getUniqueID()));
        // 订单ID
        item.setOrderId(order.getId());
        // 商品ID
        item.setGoodsId(itemDto.getGoodsId());

        GoodsVo goodsVo = goodsService.selectGoodsById(itemDto.getGoodsId());
        item.setGoodsName(goodsVo.getGoodsName());
        item.setGoodsIntro(goodsVo.getGoodsIntro());
        item.setGoodsCoverImg(goodsVo.getGoodsCoverImg());
        item.setSellingPrice(goodsVo.getSellingPrice());
        item.setGoodsCount(itemDto.getQuantity());
        item.setNeedCourseFlag(goodsVo.getNeedCourseFlag());
        item.setSpecsFlag(goodsVo.getSpecsFlag());

        if ("1".equals(itemDto.getSpecsFlag())) {
            if (null == itemDto.getSpecsId()) {
                throw new ServiceException("多规格商品规格id不能为空");
            }
            GoodsSpecsVo goodsSpecsVo = goodsSpecsService.selectGoodsSpecsById(itemDto.getSpecsId());
            if (null == goodsSpecsVo) {
                throw new ServiceException("规格不存在");
            }
            item.setSellingPrice(goodsSpecsVo.getSpecsPrice());
        }

        // 订单总价
        BigDecimal totalAmount = item.getSellingPrice().multiply(new BigDecimal(itemDto.getQuantity()));
        order.setTotalPrice(totalAmount);
        order.setPayPrice(totalAmount);
        return item;
    }

    @Override
    public void wechatPay(HttpServletRequest request) {
        Map<String, String> payMap = orderPayService.payNotify(request);
        if(null != payMap && payMap.containsKey("code")) {
            String code = payMap.get("code");
            if("SUCCESS".equals(code)) {
                // 支付成功，根据商户订单号查询订单
                OrderQueryReqDto orderQueryReqDto = new OrderQueryReqDto();
                orderQueryReqDto.setOrderNo(payMap.get("orderNo"));
                // 根据商户订单号查询订单
                OrderQueryRespVo respVo = orderPayService.queryOrder(orderQueryReqDto);
                // 根据订单号查询订单
                OrderVo orderVo = orderMapper.selectOrderBySn(respVo.getOrderNo());
                OrderDto orderDto = new OrderDto();
                // 属性拷贝
                BeanUtil.copyProperties(orderVo, orderDto);
                // 幂等
                if (OrderStatusEnum.PENDING_PAY.value() != orderDto.getOrderStatus()) {
                    log.info("Order (SN: {}) has beed paid", orderDto.getOrderNo());
                    return;
                }
                wechatPay(orderDto, respVo);
            }
        }
    }


    /**
     * 微信支付
     * @param order
     * @param respVo
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public OrderEntity wechatPay(OrderDto order, OrderQueryRespVo respVo) {
        order.setOrderStatus(OrderStatusEnum.YET_SEND.value());
        // 付款金额
        order.setPayPrice(new BigDecimal(new DecimalFormat("0.00").format((double)respVo.getPayerTotal() / 100)));
        // 微信交易号
        order.setTradeNo(respVo.getThirdPayOrderNo());
        // 付款时间
        order.setPayTime(new DateTime(respVo.getThirdSuccessTime()).toDate());
        order.setPayStatus(1);
        // 更新订单
        orderMapper.updateOrder(order);

        OrderTransDto trans = new OrderTransDto();
                trans.setId(Long.valueOf(IdUtils.getUniqueID()));
        trans.setOrderId(order.getId());
        trans.setTradeNo(order.getTradeNo());
        trans.setTranType(TranTypeEnum.PAY.value());
        trans.setTranStatus(TranStatusEnum.SUCCESS.value());
        trans.setTranAmount(respVo.getPayerTotal());
        // 创建时间
        trans.setCreateTime(new Date());
        // 保存微信交易表
        orderTransMapper.insertOrderTrans(trans);
        return order;
    }

    @Override
    public void cancel(Long orderId) {
        OrderVo orderVo = orderMapper.selectOrderById(orderId);
        OrderDto orderDto = new OrderDto();
        BeanUtil.copyProperties(orderVo, orderDto);
        // 取消类型
        orderDto.setCancelType(CancelTypeEnum.USER.value());
        // 取消时间
        orderDto.setCancelTime(new Date());
        // 订单状态
        orderDto.setOrderStatus(OrderStatusEnum.YET_CANCEL.value());
        // 修改人
        orderDto.setUpdateBy(SecurityUtils.getNickName());
        orderDto.setUpdateTime(DateUtils.getNowDate());
        // 更新订单
        orderMapper.updateOrder(orderDto);
    }

    @Override
    public void receipt(Long orderId) {
        OrderVo orderVo = orderMapper.selectOrderById(orderId);
        OrderDto orderDto = new OrderDto();
        BeanUtil.copyProperties(orderVo, orderDto);
        // 订单状态-已完成
        orderDto.setOrderStatus(OrderStatusEnum.YET_COMPLETE.value());
        // 发货时间
        orderDto.setReceiptTime(new Date());
        orderDto.setUpdateBy(SecurityUtils.getNickName());
        orderDto.setUpdateTime(DateUtils.getNowDate());
        // 更新订单
        orderMapper.updateOrder(orderDto);
    }

    @Override
    public List<OrderVo> page(OrderDto dto) {
        List<OrderVo>  orderVos = orderMapper.selectOrderList(dto);
        List<Long> orderIds = new ArrayList<>();
        orderVos.forEach(orderVo -> {
            orderIds.add(orderVo.getId());
        });
        if (orderIds.size() > 0) {
            List<OrderItemVo> orderItemVos = orderItemMapper.selectOrderItemListByOrderIds(orderIds);
            if (null != orderItemVos && orderItemVos.size() > 0) {
                orderVos.forEach(orderVo -> {
                    orderItemVos.forEach(orderItemVo -> {
                        if (orderVo.getId().longValue() == orderItemVo.getOrderId().longValue()) {
                            if (null == orderVo.getItems()) {
                                orderVo.setItems(new ArrayList<>());
                            }
                            orderVo.getItems().add(orderItemVo);
                        }
                    });
                });
            }
        }
        return orderVos;
    }

    @Override
    public OrderVo detail(Long orderId) {
        OrderVo orderVo = orderMapper.selectOrderById(orderId);
        List<OrderItemVo> orderItemVos = orderItemMapper.selectOrderItemListByOrderId(orderId);
        orderVo.setItems(orderItemVos);
        return orderVo;
    }

    @Override
    public OrderPayRespVo createPrePayOrder(String openId, Long orderId) {
        OrderVo order = orderMapper.selectOrderById(orderId);
        if (null == order) {
            throw new ServiceException("订单不存在");
        }

        List<OrderItemVo> orderItemVos = orderItemMapper.selectOrderItemListByOrderId(order.getId());
        OrderItemVo orderItemVo = orderItemVos.get(0);
        if ("1".equals(orderItemVo.getNeedCourseFlag())) {
            verifySignupNum(order.getCourseId());
        }

        OrderPayReqDto orderPayReqDto = new OrderPayReqDto();
        orderPayReqDto.setOrderType("1");
        orderPayReqDto.setDesc("商品");
        orderPayReqDto.setGoodsName("商品");
        orderPayReqDto.setTotalPrice(order.getTotalPrice().multiply(new BigDecimal(100)).intValue());
        orderPayReqDto.setOpenId(openId);
        orderPayReqDto.setOrderNo(order.getOrderNo());
        try {
            OrderPayRespVo orderPayRespVo = orderPayService.createPrePayOrder(orderPayReqDto);
            orderPayRespVo.setPayPrice(order.getTotalPrice());
            return orderPayRespVo;
        } catch (Exception e) {
            throw new ServiceException(e.getMessage());
        }
    }

    private void verifySignupNum(Long courseId) {
        CourseVo courseVo = courseMapper.selectCourseById(courseId);
        if (null == courseVo) {
            throw new ServiceException("课程数据不存在");
        }

        Integer limitNum = courseVo.getLimitNum();
        Integer signupNum = courseVo.getSignupNum();
        if (signupNum.intValue() + 1 > limitNum.intValue()) {
            throw new ServiceException("报名人数已满");
        }
    }
}
